Skip to main content

Conditions, Loops and Iterators

In this section we will see how Python programs use conditional statements, perform loops and iterate over data structures.

Conditional Statements

Conditional statements are tests on a specific value, an expression that evaluates to a boolean value (True or False). The value may be a literal value or a variable. To test a condition of a value in Python we predominantly, but not always, use the ‘If-then-else’ construct.

Let's look at a simple example:

base = 10
number = int(input("give me a number"))

if number > 10:
print("number is greater than 10")
base = number - base
elif number < 10:
print("number is less than 10")
base += number
else:
print("number is equal to base")

# This executes after the if statement
print(f"base is {base}")

In the above example, for each part of a condition we separate our tests on separate lines, using a colon : to terminate that particular conditional test. As always, our code is tabulated as per the Python syntax rules.

The variable base is initialised to '10', the user inputs a number, and we start comparing. Notice the elif keyword. This is Python shorthand for else if Depending on the number input by the user we print a statement before finally, after the comparison has ended, printing the base.

Python allows as many elif parts as are necessary. However, it is advisable to keep these to a readable level. You can also test for Truth by simply checking if a value is True or False.

always = True
if always:
print("Always and Forever")
else:
print("Never say Never")

An alternative for a simple True/False comparison would be to use a ternary expression.

A ternary expression has 3 parts: result, comparison, result.

always = False  
# A simple ternary comparison
print("Always and Forever") if always else print("Never say Never")

It is also possible to combine comparisons in a ternary expressions.

number1 = int(input("number1: "))
number2 = int(input("number2: "))
# Always sum absolute values of the numbers
number3 = (number1 if number1 > 0 else -number1) + (number2 if number2 > 0 else -number2)
print(number3)

In the above example we have two if else comparison statements, the results of which will always return positive values.

We can perform if statements on data structures by using various methods, a couple of examples on lists and dictionaries:

cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']

if "Audi" in cars:
print("Audi is there")
else:
print("Audi is Not there")

In the above we use the in operator to ask Python if 'Audi' is in the list.

tayfun = {'name':'Tayfun', 'job': 'Software engineer', 'car': 'BMW'}

if tayfun.get('car') == "BMW":
print("Tayfun has a BMW, lucky him!")
else:
print("Never Mind - Keep saving your pocket money")

Above we access the key car by using the get method on the dictionary tayfun. If it has a key called car it returns the value and compares it with BMW. When testing dictionaries, if you aren't sure that the will be a certain key in the dictionary always use the get method and not tayfun['car']. The get method will not break your code with an KeyError if the key does not exist. It will simply equate to False and continue to the next part of the conditional statement or code.

Match Statements

For a long time Python did not have a 'Switch' statement for comparing simple values, but as of 3.10, it has introduced the match statement.

A Match statement is a conditional statement that is used instead of if then else statements depending on the test condition. Match statements generally test against single values rather than expressions involving operators.

Larger value sets are more efficient when using a match statement and are often more readable than multiple if-then-else statements. A general rule of thumb is if there are more than 5 simple comparison conditions use a match rather than if-then-else.

Once a code block from a match has executed the 'match' statement is exited.

color = input("Give me a color ('red', 'yellow', or 'green'):")

match color:
case "red":
print("Red means STOP")
case "yellow":
print("Yellow means PREPARE to go or stop")
case "green":
print("Green means GO")
case _: # Default block to execute if no match
print("I do not understand")

This above is equivalent to the following:

color = input("Give me a color ('red', 'yellow', or 'green'):")

if color == "red":
print("Red means STOP")
elif color == "yellow":
print("Yellow means PREPARE to go or stop")
elif color == "green":
print("Green means GO")
else: # Default block to execute if no match
print("I do not understand")

Identity Operators

Python offers a couple of operators for matching in conditional statements, is, is not. Although using is not is common place when you compare variables, it is recommended that you use != when you have a literal either side of the conditional statement.

tayfun = {'name':'Tayfun', 'job': 'Software engineer', 'car': 'BMW'}
richard= {'name':'Richard', 'job': 'Baker', 'car': 'Niva'}
job = "Baker"

if tayfun.get('car') is "BMW" and tayfun.get('job') is not 'Baker':
print("Tayfun has a good job and can afford a BMW, lucky him!")
else:
print("Never Mind Tayfun, think about a career change")

Logical Operators

Python offers three logical operators that can be used in conditional statements, and, or, not. and and not are commonly used together as and not.

Check out the following examples

x = False
y = False
z = True

if not x and (not y or z):
print("Logic makes the world go around")

Change x to True and run again

tayfun = {'name':'Tayfun', 'job': 'Software engineer', 'car': 'BMW'}
richard= {'name':'Richard', 'job': 'Baker', 'car': 'Niva'}

if tayfun.get('car') == "BMW" and tayfun.get('job') == 'Software engineer':
print("Tayfun has a good job and can afford a BMW, lucky him!")
else:
print("Never Mind Tayfun, think about a career change")

if richard.get('car') == "BMW" or richard.get("car") == "Mercedes" and not richard.get('job') == 'Baker':
print("Richard has a good job and can afford a nice car, lucky him!")
else:
print("Richard, everyone needs bread, you're doing a good job!")

For a comprehensive list of all Python operators see Python Operators

Iterating (looping) over objects and data structures

Remember that everything in Python is an object, but not everything is iterable, strings, lists, tuples, dictionaries are iterable, anything that has a countable number of values. Numbers i.e. integers and floats are not iterable.

When we use data structures, we often need to iterate over (run through all the values) and do some processing or calculations. Python offers various iteration constructs to facilitate iteration. These are known as ‘Loops’, because we generally, but not always, loop over an object one item at a time.

There are two common ways to loop over objects. The ‘For Loop’ and the 'While Loop'

For Loops

For loops have a couple of useful keywords that can effect the flow of the loop.

  1. break - Breaks the current loop and continues with the rest of the code
  2. continue - continue with the loop - used often with conditions within a loop

For Loops often use an explicit variable counter that gets incremented on each loop to a maximum (generally the number of items in the object) to loop over an object starting normally at the start (0) but not always. Using this method you can iterate over an object starting at any position you want, even in reverse if necessary. Some languages use a ‘for each’ or ‘For in’ construct which loops over each item in the object until the end is reached.

Iterating over numbers You can use the range() function to iterate over a certain set of numbers.

# Print even numbers from 1 to 10
for i in range(1, 10):
if i % 2 == 0:
print(i)

You can use a third range parameter to skip over certain indexes.

for number in range(10, 110, 10):
print(number)

Iterating over strings with a for loop

my_name = "Michael Caine"
statement = "Not a lot of people know that"

for i in my_name:
print(i)

for i in statement:
print(i, end="")

The first loop prints each character of the string on a separate line, whilst the second uses the end="" condition, which ensures the characters are print statements stay on the same line.

Let's be clever and replace all the vowels in the statements with an * character.

statement = "My name is Michael Caine - Not a lot of people know that"
vowels = ['a', 'e', 'i', 'o', 'u']

for i in statement:
if i in vowels:
i = "*"
print(i, end="")

Iterating over lists with a for loop

Let's iterate over a list and print out each item.

cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']
for car in cars:
print(car)

The code above is about as simple as it gets. Now let's introduce a condition and once met terminate the loop using a break statement and a simple counter function to count the iterations before we satisfy the condition

count = 0
cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']
my_car = "Land Rover"
for car in cars:
count += 1
if car == my_car:
print("My car = ", car)
break

print("number of iterations = ", count)

As you will find out if you run this in the Python Console, we iterated to the 4th element to match the condition, and then broke out of the loop using the break statement.

We can, if required, iterate in reverse using the reverse function.

count = 0
cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']
my_car = "Land Rover"
for car in reversed(cars):
count += 1
if car == my_car:
print("My car = ", car)
break

print("number of iterations = ", count)

Now the number of iterations is less, 3 to be exact.

You can skip items of a data structure whilst looping using a number of methods

# Using the slice method on the list.
cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']

# Start iterating after the first two items
for car in cars[2:]:
print(car)
cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']

# Using the slice method on the list. Start iterating after but stop before you hit the last 2 items
for car in cars[:-2]:
print(car)

If you wanted to be clever you could even iterate over a list from both ends meeting in the middle

cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']
for i in range((len(cars) + 1) // 2):
print(cars[i], cars[~i])

Above we use the ~ operator to give us the negative power of the index -(i *1). Thus, we get an item from the front of the list and then from the back using the negative number.

Iterating over tuples

Iterating over tuples is much the same as lists...

cars = ('Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda')
for car in cars:
print(car)

And so on...

count = 0
cars = ('Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda')
my_car = "Land Rover"
for car in cars:
count += 1
if car == my_car:
print("My car = ", car)
break

print("number of iterations = ", count)
# Using the slice method on the tuple.
cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']

# Start iterating after the first two items
for car in cars[2:]:
print(car)
cars = ('Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda')
for i in range((len(cars) + 1) // 2):
print(cars[i], cars[~i])

Iterating over a set

cars = {'Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda'}
for i in cars:
print(i)

Iterating over Dictionaries

Iterating over dictionaries is slightly different although the principles are the same we need to use the items method on the dictionary.

auto_club = {"Audi": {"owners":["Jeff", "Mary", "Bob"], "model": "Quattro"}, 
"Land Rover": {"owners":["Richard", "Hank"], "model": "Range Rover"},
"Honda": {"owners":["Rebecca", "Louise", "Ted", "Sophie"], "model": "Prelude"}}

# We have two parameters representing the key and the value of each item in the dictionary.
for i in auto_club.items():
print(i)

If you want to you can set two iteration variables instead of one. i.e. k,v instead of i. this is useful if you only want to get the values and not the keys.

auto_club = {"Audi": {"owners":["Jeff", "Mary", "Bob"], "model": "Quattro"}, 
"Land Rover": {"owners":["Richard", "Hank"], "model": "Range Rover"},
"Honda": {"owners":["Rebecca", "Louise", "Ted", "Sophie"], "model": "Prelude"}}

# We have two parameters representing the key and the value of each item in the dictionary.
for k, v in auto_club.items():
print(v)

In the case above you could also make k anonymous by using and _ underscore instead of the k.

Or reverse the situation and just access the keys, but there are easier ways to get both all the keys and all the values without the bother to iterate.

As described in 'Data Structures' in part two you can just use the keys and values methods on dictionaries to retrieve either.

For iteration purposes you can also use those methods.

auto_club = {"Audi": {"owners":["Jeff", "Mary", "Bob"], "model": "Quattro"}, 
"Land Rover": {"owners":["Richard", "Hank"], "model": "Range Rover"},
"Honda": {"owners":["Rebecca", "Louise", "Ted", "Sophie"], "model": "Prelude"}}

print("keys -->")
for i in auto_club.keys():
print(i, end=" ")
print("\n\nvalues -->")
for i in auto_club.values():
print(i)

While Loops

While loops differ from 'For Loops' in as much as the loop continues until a condition is met.

name = "Richard"
result = ""
i = 0
while result != name:
result += name[i]
i += 1

print(result)
print(i)

The while loop above will keep running until result is equal to name. It uses a parameter i as the index count of name. Taking the character at each position and adding this to result.

The following uses a while loop to test values in a list.

cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']
match = False
my_car = 'Toyota'
i = 0
while not match:
if cars[i] == my_car:
print("found my car model")
match = True
i += 1

print('i=',i)

The following uses a while loop to test values in a dictionary.

auto_club = {"Audi": {"owners":["Jeff", "Mary", "Bob"], "model": "Quattro"}, 
"Land Rover": {"owners":["Richard", "Hank"], "model": "Range Rover"},
"Honda": {"owners":["Rebecca", "Louise", "Ted", "Sophie"], "model": "Prelude"}}

model = False
while model is False:
for k, v in auto_club.items():
if v['model'] == 'Prelude':
print("found a Honda Prelude which is owned by ", v['owners'])
model = True

Note the above could be coded more simply without the while loop as:

auto_club = {"Audi": {"owners":["Jeff", "Mary", "Bob"], "model": "Quattro"}, 
"Land Rover": {"owners":["Richard", "Hank"], "model": "Range Rover"},
"Honda": {"owners":["Rebecca", "Louise", "Ted", "Sophie"], "model": "Prelude"}}

for k, v in auto_club.items():
if v['model'] == 'Prelude':
print("found a Honda Prelude which is owned by ", v['owners'])
model = True
break

Object Iterators outside loops

We have covered loops which iterate over certain objects and data structures, now let's look at iterators themselves. Iterators are, as previously stated above, are special methods that iterate over objects that are countable.

Let's look at a list iterator:

cars = ['Audi', 'BMW', 'Mercedes', 'Land Rover', 'Toyota', 'Honda']
my_iter = iter(cars)

print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))

As can be seen above we use the iter() method with the cars as the parameter to get an iterator from the cars list. We then print each item in turn using the next method.

The same can be done with strings, dictionaries and tuples.

Here's an example using a string iterator

my_str = "Richard"
my_iter = iter(my_str)

print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))
print(next(my_iter))

That's it for this section, you can move on to the next part of this tutorial.